/**
 * System库函数: 执行操作系统(cmd)的命令 or 运行指定程序
 */
#include <stdlib.h>
#include <stdio.h>

void system_test();
void array2Int_Long_Float();
void int_Long_Float2Array();
int rand_test();
void exit_test();
void malloc_free();
void malloc_2_array();
void level2_pointer_malloc();

int main() {
    //1.system
//    system_test();
//    //2.array --> int, long, float
//    array2Int_Long_Float();
//    //3.int, long, float --> array
//    int_Long_Float2Array();
//    //4.srand, rand
//    rand_test();
//    //5.exit 终止程序执行
//    exit_test();
    //5.malloc() 开辟堆空间 & free()释放空间
    malloc_free();
    //6.malloc() 开辟堆空间, 用作数组
    malloc_2_array();
    //7. 2级指针对应的堆空间
    level2_pointer_malloc();

    return EXIT_SUCCESS;
}

/**
 * 1.system 函数
 *   System 返回值, 在windows 和 unix 下的不同
 */
void system_test() {
    system("cls");         //清屏
    system("calc");        //打开计算器
    system("mspaint");     //画图板
    system("notepad");     //打开TXT文本文档
    system("osk");         //软键盘
    system("pause");       //程序执行到这儿暂停(防止程序一闪而过, 看不到结果)(win7编译器, 需要暂停, 否则黑框一闪而过)

    system("D:\\Desktop\\FeiQ.exe");//打开软件
    system("D:/Desktop/FeiQ.exe");  //打开软件
    int j = system("a");             //执行a.exe

    while(j) {               //关掉后才会再打开一个,会一直打开
        system("notepad");
    }
}

/**
 * 2.Array --> int, long, float https://www.bilibili.com/video/BV1vs411n7TH?p=88
 *   stdlib.h, 标准C语言库函数.
 *   atoi:
 *      忽略前方空格, 直到遇到'数字/±号'才开始转换, 遇到 '非数字' or '\0' 才停止.
 */
void array2Int_Long_Float() {
    char arr1[100] = "  -200abc123";
    char arr3[100] = "  -300.456abc123";
    int i = atoi(arr1);      //-200
    long l = atol(arr3);     //-300
    double d = atof(arr3);   //-300.456
    printf("i = %d\n", i);
    printf("l = %ld\n", l);
    printf("d = %lf\n", d);
}

/**
 * 3.int, long, float --> Array
 */
void int_Long_Float2Array() {
    char array[100] = {0};
    /**
     * int转字符串
     * 不是标准C语言库函数(Linux 没有这个函数), 可用 sprintf 转换(stdio.h)
     * 参1: 要转换的int值.
     * 参2: ?.
     * 参3: ?.
     * @return ?
     */
    char * aint = itoa(123, array, 2);
    char *along = ltoa(12345L, array, 3);
    printf("int --> array: %s", aint);
    printf("long --> array: %s", along);
}

/**
 * 4.获得随机数
 */
#include <time.h>
int rand_test() {
    //<time.h> 得到系统时间, unsigned int 类型
    time_t tm = time(NULL);
    //<stdlib.h> 随机数种子发生器, 写在 rand();之前, 否则 rand();每次产生的随机数都一样
    srand(tm);
    //<stdlib.h> 生成随机数, 0~RAND_MAX(2^31 - 1: 2147483647)
    int r = rand();
    return r;
}

/**
 * 5.exit 终止程序执行
 */
void exit_test() {
    //终止程序执行
    exit(-1);
}

/**
 * 5.开辟堆空间: void *__cdecl malloc(size_t _Size);
 *   在内存的动态存储区(堆区)中分配1块长度为size字节的连续区域,
 *   用来存放类型说明符指定的类型, 分类的内存空间内容不确定,
 *   一般使用 memset() 初始化.
 * @param size 需要分配内存大小(单位: 字节Byte)
 * @return 成功: 返回分配空间的起始位置.
 *         失败: 返回NULL
 */
//#include <malloc.h>
void malloc_free() {
    int size = sizeof(int) * 10;    //开辟10个int空间的字节
    int *p1 = (int*) malloc(size);   //将 void * 强转成 int*
    if (p1 == NULL) return;
    printf("&p1 = %p\n", &p1);

    //使用堆空间
    *p1 = 123;
    printf("赋值后: p1 = %d\n", *p1);

    /**
     * 可传入 NULL
     * 释放空间: void __cdecl free(void *_Memory);
     */
    free(p1);
//    p1 = NULL;                            //释放后, 应该置 NULL
    printf("释放后: &p1 = %p\n", &p1);       //p1现在是野指针

//    *p1 = 456;                              //有时候会报错, 有时候不会
    printf("释放后再赋值: p1 = %d\n", *p1);   //456
}

/**
 * 6.malloc() 开辟堆空间, 用作数组
 * https://www.bilibili.com/video/BV1vs411n7TH/?p=97
 */
void malloc_2_array() {
    int size = sizeof(int) * 10;    //开辟10个int空间的字节
    //2.申请后转成数组
    int *p2 = (int*) malloc(size);
    for (int i = 0; i < 10; ++i) p2[i] = i;
    for (int i = 0; i < 10; ++i) {
//        printf("p2[%d] = %d\n", i, p2[i]);    //正确打印
//        printf("p2[%d] = %d\n", i, *(p2 + i));//正确打印
        /**
         * https://www.bilibili.com/video/BV1vs411n7TH?p=98
         * 指针在一直往上+
         */
        printf("p2[%d] = %d\n", i, *p2++);
    }
    /**
     * 释放的时候, 有可能会报错, 因为指针位置不再是p2原始位置
     * 可以将指针重置: p2 -= 10;
     */
    free(p2);
    p2 = NULL;
}

/**
 * 2级指针对应的堆空间: https://www.bilibili.com/video/BV1vs411n7TH?p=102
 */
void level2_pointer_malloc() {
    int sizeI = sizeof(int);
    //int[5][3]
    int **pp = malloc(sizeI * 5);   //开辟2级指针的堆空间, 5行
    for (int i = 0; i < 5; ++i) {
        pp[i] = malloc(sizeI * 3);  //开辟1级指针的堆空间, 3列
        for (int j = 0; j < 3; ++j) {
            pp[i][j] = i * 3 + j * 3 + 3; //元素赋值
        }
    }
    for (int i = 0; i < 5; ++i) {
        for (int j = 0; j < 3; ++j) {
            printf("pp[%d][%d] = %d ", i, j, pp[i][j]);
        }
        puts("");
    }

    //释放
    for (int i = 0; i < 5; ++i) {
        free(pp[i]);            //先释放里面的1级指针
    }
    free(pp);
    pp = NULL;
}